package rlpw.swing;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

abstract class StateModel<T> implements Mode {

    private View<T> view;
    private Set<T> states = new HashSet<T>();
    private int mode = SelectModel.MULTIPLE;

    public StateModel(View<T> view) {
        this.view = view;
    }

    public boolean getState(int index) {
        return states.contains(new FilteredList<T>(view).get(index));
    }

    public boolean getState(T element) {
        return states.contains(element);
    }

    public int size() {
        return states.size();
    }

    public void setState(int index, boolean check) {
        setState(new FilteredList<T>(view).get(index), check);
    }

    public void setState(T element, boolean check) {

        if (getMode() == Mode.SINGLE && states.contains(element)) {
            return;
        }

        if (check) {

            states.add(element);
            if (getMode() == Mode.SINGLE || (getMode() == Mode.INTERVAL && !isInterval())) {
                states.clear();
                states.add(element);
            }
        } else {
            states.remove(element);
            if (getMode() == Mode.INTERVAL && !isInterval()) {
                states.clear();
            }
        }

        view.updateView();
    }

    public void setAllState(boolean check) {
        if (check) {
            if (!(getMode() == Mode.SINGLE)) {
                states = new HashSet(view.getDataModel());
            }
        } else {
            states.clear();
        }

        view.updateView();
    }

    public List<T> getStates() {
        return new ArrayList(states);
    }

    private boolean isInterval() {

        FilteredList<T> fl = new FilteredList<T>(view);
        List<Integer> ls = new ArrayList<Integer>();

        for (T e : states) {
            ls.add(fl.indexOf(e));
        }

        Collections.sort(ls);

        int lastIndex = -1;
        for (int index : ls) {
            if (lastIndex == -1 || lastIndex + 1 == index) {
                lastIndex = index;
            } else {
                return false;
            }
        }

        return true;
    }

    public void setMode(int mode) {
        this.mode = mode;
        states.clear();
        view.updateView();
    }

    public int getMode() {
        return mode;
    }
}
